package com.jumi.microservice.service.logistics.admin;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.common.page.TableDataInfo;
import com.jumi.microservice.domain.GoodsInfoDTO;
import com.jumi.microservice.domain.TransferWarehouseDTO;
import com.jumi.microservice.dto.logistics.*;
import com.jumi.microservice.dto.logistics.admin.WarehouseListResponse;
import com.jumi.microservice.dto.order.OrderLogRequest;
import com.jumi.microservice.entity.LogisticsGoods;
import com.jumi.microservice.entity.OrderLogistics;
import com.jumi.microservice.entity.UserOrder;
import com.jumi.microservice.enumerate.LogisticsStatusEnum;
import com.jumi.microservice.enumerate.OrderStatusEnum;
import com.jumi.microservice.enumerate.SpiltMergeStatusEnum;
import com.jumi.microservice.mapper.LogisticsGoodsMapper;
import com.jumi.microservice.mapper.OrderGoodsMapper;
import com.jumi.microservice.mapper.OrderLogisticsMapper;
import com.jumi.microservice.mapper.UserOrderMapper;
import com.jumi.microservice.material.dto.supplier.JmSupplierResponse;
import com.jumi.microservice.material.dto.warehouse.JmWarehouseResponse;
import com.jumi.microservice.material.service.IJmSupplierService;
import com.jumi.microservice.material.service.IJmWarehouseService;
import com.jumi.microservice.service.BasicDataService;
import com.jumi.microservice.service.IOrderDubboService;
import com.jumi.microservice.service.IOrderInventoryService;
import com.jumi.microservice.service.logistics.AutoSpiltService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author by mazhao
 * @Classname RelocateService
 * @Description TODO
 * @Date 2020/8/19 15:38
 */
@Service
public class RelocateService {

    @Resource
    LogisticsGoodsMapper logisticsGoodsMapper;

    @Resource
    OrderGoodsMapper orderGoodsMapper;

    @Resource
    OrderLogisticsMapper orderLogisticsMapper;

    @Resource
    AutoSpiltService autoSpiltService;

    @DubboReference
    IJmWarehouseService iWarehouseService;

    @DubboReference
    BasicDataService basicDataService;

    @DubboReference
    IJmSupplierService iSupplyService;

    @DubboReference
    IOrderInventoryService iOrderInventoryService;

    @Resource
    SendService sendService;

    /**
     * 查询某个时间段内的所有未发货订单
     * @return
     */
    public TableDataInfo<RelocateGoodsListResponse> getRelocateGoodsList(RelocateGoodsListRequest request){
        TableDataInfo<RelocateGoodsListResponse> tableDataInfo = new TableDataInfo<>();
        List<RelocateGoodsListResponse> result = new ArrayList<>();
        Page<Map<String,BigDecimal>> page = new Page<>(request.getPageNum(),request.getPageSize());
        IPage<Map<String, Object>> iPage = logisticsGoodsMapper
                .goodsSpuStatistics(request.getRealWarehouse(),request.getGoodsName()!=null && !request.getGoodsName().trim().isEmpty()?"%"+request.getGoodsName()+"%":null,request.getStartTime(),request.getEndTime(),page);
        List<Map<String,Object>> goodsSpuList = iPage.getRecords();
        if(goodsSpuList.isEmpty()){
            tableDataInfo.setRows(result);
            tableDataInfo.setTotal(iPage.getTotal());
            return tableDataInfo;
        }
        List<Long> ids = goodsSpuList.stream().map(m->Long.valueOf(m.get("spuId").toString())).collect(Collectors.toList());
        Map<Integer,GoodsInfoDTO> spuMap = getGoodsSpuInfo(ids);
        for(Map<String, Object> m:goodsSpuList){
            RelocateGoodsListResponse relocateGoodsListResponse = new RelocateGoodsListResponse();
            if(!spuMap.containsKey(m.get("spuId"))){
                continue;
            }
            relocateGoodsListResponse.setBrand(spuMap.get(m.get("spuId")).getBrandName());
            relocateGoodsListResponse.setSpuName(spuMap.get(m.get("spuId")).getGoodsName());
            relocateGoodsListResponse.setSpuStatus(spuMap.get(m.get("spuId")).getGoodsState());
            relocateGoodsListResponse.setSort(spuMap.get(m.get("spuId")).getCategoryName());
            relocateGoodsListResponse.setSpuCoverImg(spuMap.get(m.get("spuId")).getGoodsImage());
            relocateGoodsListResponse.setSpuId(Integer.parseInt(m.get("spuId").toString()));
            relocateGoodsListResponse.setGoodsAmount(Integer.parseInt(m.get("goodsAmount").toString()));
            relocateGoodsListResponse.setOrderAmount(Integer.parseInt(m.get("orderAmount").toString()));
            result.add(relocateGoodsListResponse);
        }
        tableDataInfo.setRows(result);
        tableDataInfo.setTotal(iPage.getTotal());
        return tableDataInfo;
    }


    /**
     *
     * @return
     */
    public List<RelocateRepoListResponse> getRelocateWarehouseList(RelocateRepoListRequest request){
        //请求接口获取仓库信息
        Map<Integer,JmWarehouseResponse> warehouseInfoMap = getWarehouseInfo();
        Integer warehouseId = null;
        if(request.getWarehouse()!=null && !request.getWarehouse().trim().isEmpty()) {
            warehouseId =  getWarehouseId(request.getWarehouse(),warehouseInfoMap);
        }
        List<RelocateRepoListResponse> result = new ArrayList<>();
        if(warehouseId!=null && warehouseId==-1) {
            return result;
        }
        List<Map<String, Object>> warehouseMapList = logisticsGoodsMapper.warehouseStatistics(warehouseId,request.getStartTime(),request.getEndTime());
        for(Map<String, Object> m:warehouseMapList){
            RelocateRepoListResponse relocateRepoListResponse = new RelocateRepoListResponse();
            relocateRepoListResponse.setWarehouseId((int) m.get("warehouse"));
            relocateRepoListResponse.setWarehouseName(warehouseInfoMap.get(m.get("warehouse")).getWarehouseName());
            relocateRepoListResponse.setWarehouseAddress(warehouseInfoMap.get(m.get("warehouse")).getAddress());
            relocateRepoListResponse.setGoodsAmount(Integer.parseInt(m.get("goodsAmount").toString()));
            relocateRepoListResponse.setOrderAmount(Integer.parseInt(m.get("orderAmount").toString()));
            result.add(relocateRepoListResponse);
        }
        return result;
    }

    /**
     *根据仓库名称获取仓库ID
     * @param warehouseName
     * @param map
     * @return
     */
    public Integer getWarehouseId(String warehouseName,Map<Integer,JmWarehouseResponse> map){
        for(Integer key:map.keySet()){
            if(map.get(key).getWarehouseName().contains(warehouseName)) {
                return key;
            }
        }
        return -1;
    }


    @Resource
    UserOrderMapper userOrderMapper;

    /**
     * 修改仓库提交
     *
     * @param request
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean relocateSubmit(RelocateSubmitRequest request,Long uid,String name) {
        QueryWrapper<LogisticsGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("del_flag", 0).eq("spu_id", request.getSpuId())
                .eq("logistics_status", LogisticsStatusEnum.WAIT_SEND.getCode())
                .eq("real_warehouse", request.getOldWarehouse())
                .ge("create_time",request.getStartTime())
                .le("create_time",request.getEndTime());
        List<LogisticsGoods> list = logisticsGoodsMapper.selectList(queryWrapper);
        if(list.isEmpty()){
            throw new BaseException(500,"当前SPU下无符合条件商品");
        }
        List<TransferWarehouseDTO> transferWarehouses = new ArrayList<>();
        List<String> orderNoList = new ArrayList<>();
        List<String> logisticsNoList = new ArrayList<>();
        List<String> orderNos = list.stream().map(LogisticsGoods::getOrderNo).collect(Collectors.toList());
        QueryWrapper<UserOrder> userOrderQueryWrapper = new QueryWrapper<>();
        userOrderQueryWrapper.in("order_no",orderNos).eq("order_status", OrderStatusEnum.READY_TO_SHIP.getCode());
        List<UserOrder> userOrderList = userOrderMapper.selectList(userOrderQueryWrapper);
        orderNos = userOrderList.stream().map(UserOrder::getOrderNo).collect(Collectors.toList());
        for(LogisticsGoods g:list){
            if(!orderNos.contains(g.getOrderNo())){
                continue;
            }
            TransferWarehouseDTO transferWarehouseDTO = new TransferWarehouseDTO();
            transferWarehouseDTO.setGoodsSkuId(g.getGoodsId().longValue());
            transferWarehouseDTO.setNewWarehouseId(request.getNewWarehouse().longValue());
            transferWarehouseDTO.setOldWarehouseId(g.getRealWarehouse().longValue());
            transferWarehouseDTO.setSaleStockQuantity(g.getGoodsAmount());
            transferWarehouses.add(transferWarehouseDTO);
            g.setRealWarehouse(request.getNewWarehouse());
            sendService.addLog(uid,name,g.getOrderNo(),"订单调仓操作 "+g.getGoodsName()+
                    "，数量："+g.getGoodsAmount()+"，原仓ID："+g.getRealWarehouse()+"，调整为："+request.getNewWarehouse());
            orderNoList.add(g.getOrderNo());
            logisticsNoList.add(g.getLogisticsNo());
        }
        if(iOrderInventoryService.transferWarehouseEvent(transferWarehouses)){
            //修改包裹商品为未确认包裹状态
            logisticsGoodsMapper.batchUpdateRealWarehouse(list);
            //修改包裹为为确认包裹状态
            orderLogisticsMapper.batchUpdateIsSpiltMergeConfirm(logisticsNoList,(byte)0);
            //修改订单商品的发货仓信息
            orderGoodsMapper.batchUpdateRealWarehouse(list);
            spiltPackage(list);
            return true;
        }
        return false;
    }



    /**
     * 提交调仓后根据最新发货仓拆包裹
     * @param paramList
     */
    public void spiltPackage(List<LogisticsGoods> paramList){
        List<String> list = paramList.stream().map(LogisticsGoods::getLogisticsNo).collect(Collectors.toList());
        Set<String> set = new HashSet<>(list);
        Map<String, OrderLogistics> logisticsInfoMap = getLogisticsInfo(set);
        List<LogisticsGoods> newGoodsList = new ArrayList<>();
        List<OrderLogistics> newLogisticsList = new ArrayList<>();
        List<OrderLogistics> updateWarehouseLogisticsList = new ArrayList<>();
        List<OrderLogistics> updateSpiltMergeStatusLogisticsList = new ArrayList<>();
        for(String logisticsNo:set){
            List<LogisticsGoods> goodsList = paramList.stream().filter(l->l.getLogisticsNo().equals(logisticsNo)).collect(Collectors.toList());
            if(isHaveGoods(logisticsNo,goodsList)){
                String newLogisticsNo = autoSpiltService.getRandomString();
                for(LogisticsGoods logisticsGoods:goodsList){
                    logisticsGoods.setLogisticsNo(newLogisticsNo);
                    newGoodsList.add(logisticsGoods);
                }
                OrderLogistics oldOrderLogistics = logisticsInfoMap.get(logisticsNo);
                oldOrderLogistics.setSpiltMergeStatus(SpiltMergeStatusEnum.SPILT.getCode());
                updateSpiltMergeStatusLogisticsList.add(oldOrderLogistics);
                OrderLogistics orderLogistics = new OrderLogistics();
                BeanUtils.copyProperties(oldOrderLogistics,orderLogistics);
                orderLogistics.setId(null);
                orderLogistics.setWarehouse(goodsList.get(0).getRealWarehouse());
                orderLogistics.setLogisticsNo(newLogisticsNo);
                orderLogistics.setSpiltMergeStatus(SpiltMergeStatusEnum.SPILT.getCode());
                newLogisticsList.add(orderLogistics);
                continue;
            }
            OrderLogistics orderLogistics = logisticsInfoMap.get(logisticsNo);
            orderLogistics.setWarehouse(goodsList.get(0).getRealWarehouse());
            updateWarehouseLogisticsList.add(orderLogistics);
        }
        if(!newGoodsList.isEmpty()) {
            logisticsGoodsMapper.batchUpdateLogisticsNo(newGoodsList);
        }
        if(!updateSpiltMergeStatusLogisticsList.isEmpty()) {
            orderLogisticsMapper.batchUpdateSpiltMergeStatusById(updateSpiltMergeStatusLogisticsList);
        }
        if(!updateWarehouseLogisticsList.isEmpty()) {
            orderLogisticsMapper.batchUpdateRealWarehouse(updateWarehouseLogisticsList);
        }
        if(!newLogisticsList.isEmpty()) {
            orderLogisticsMapper.batchInsertLogistics(newLogisticsList);
        }
    }

    /**
     * 判断包裹
     * @param logisticsNo
     * @param goodsList
     * @return
     */
    public boolean isHaveGoods(String logisticsNo,List<LogisticsGoods> goodsList){
        QueryWrapper<LogisticsGoods> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("del_flag",0).eq("logistics_no",logisticsNo);
        List<LogisticsGoods> logisticsGoodsList = logisticsGoodsMapper.selectList(queryWrapper);
        List<Integer> goodsIdList = logisticsGoodsList.stream().map(LogisticsGoods::getGoodsId).collect(Collectors.toList());
        goodsIdList.removeAll(goodsList.stream().map(LogisticsGoods::getGoodsId).collect(Collectors.toList()));
        return goodsIdList.size() >0;
    }

    /**
     *获取包裹信息
     * @param logisticsNoList
     * @return
     */
    public Map<String, OrderLogistics> getLogisticsInfo(Set<String> logisticsNoList){
        QueryWrapper<OrderLogistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("del_flag",0).in("logistics_no",logisticsNoList);
        List<OrderLogistics> list = orderLogisticsMapper.selectList(queryWrapper);
        Map<String, OrderLogistics> map = new HashMap<>(list.size());
        for(OrderLogistics orderLogistics:list){
            map.put(orderLogistics.getLogisticsNo(),orderLogistics);
        }
        return map;
    }

    /**
     * 仓库列表
     * @return
     */
    public List<WarehouseListResponse> warehouseList(){
        List<WarehouseListResponse> result = new ArrayList<>();
        List<JmWarehouseResponse> list = iWarehouseService.findAll().getData();
        for (JmWarehouseResponse jmWarehouseResponse:list){
            WarehouseListResponse warehouseListResponse = new WarehouseListResponse();
            warehouseListResponse.setWarehouseId(jmWarehouseResponse.getWarehouseId().intValue());
            warehouseListResponse.setWarehouseName(jmWarehouseResponse.getWarehouseName());
            result.add(warehouseListResponse);
        }
        return result;
    }

    /**
     * 供应商列表
     * @return
     */
    public List<SupplyListResponse> supplyList(){
        List<SupplyListResponse> result = new ArrayList<>();
        List list = iSupplyService.list().getData();
        for (Object object:list){
            JmSupplierResponse jmSupplierResponse = JSON.parseObject(JSON.toJSONString(object),JmSupplierResponse.class);
            SupplyListResponse supplyListResponse = new SupplyListResponse();
            supplyListResponse.setSupplyId(jmSupplierResponse.getSupplierId().intValue());
            supplyListResponse.setSupplyName(jmSupplierResponse.getSupplierCompanyName());
            result.add(supplyListResponse);
        }
        return result;
    }

    /**
     * 获取全部仓库信息
     * @return
     */
    public Map<Integer,JmWarehouseResponse> getWarehouseInfo(){
        List<JmWarehouseResponse> list = iWarehouseService.findAll().getData();
        Map<Integer,JmWarehouseResponse> map = new HashMap<>(list.size());
        for(JmWarehouseResponse jmWarehouseResponse:list){
            map.put(jmWarehouseResponse.getWarehouseId().intValue(),jmWarehouseResponse);
        }
        return map;
    }

    /**
     * 获取全部SPU信息
     * @return
     */
    public Map<Integer,GoodsInfoDTO> getGoodsSpuInfo(){
        List<GoodsInfoDTO> list = basicDataService.getGoodsInfoByIds(null);
        Map<Integer,GoodsInfoDTO> map = new HashMap<>(list.size());
        for(GoodsInfoDTO goodsInfoDTO:list){
            map.put(goodsInfoDTO.getId().intValue(),goodsInfoDTO);
        }
        return map;
    }

    /**
     * 获取指定SPU信息
     * @return
     */
    public Map<Integer,GoodsInfoDTO> getGoodsSpuInfo(List<Long> ids){
        List<GoodsInfoDTO> list = basicDataService.getGoodsInfoByIds(ids);
        Map<Integer,GoodsInfoDTO> map = new HashMap<>(list.size());
        for(GoodsInfoDTO goodsInfoDTO:list){
            map.put(goodsInfoDTO.getId().intValue(),goodsInfoDTO);
        }
        return map;
    }

}
